#include <SDL/SDL.h>
#include "player.h"
#include <iostream>
#include <stdio.h>

BMPlayer::BMPlayer(){
	BMCreature::BMCreature();
    camera.reset();
	speed = 0.05f;
	viewport.x = x;
	viewport.y = y;
	viewport.z = z;
	constview.x = 0;
	constview.y = 1.00;
	constview.z = -0.47f;
	vertical = 1;
	first_person = 0;
	/*/////////////////
	[1] top left front
	[2]  bottom left front
	[3]bottom right front
	[4]top right front
	[5] top left back
	[6]bottom left back
	[7]bottom right back
	[8] top right back
	*//////////////////
	/*float q = 0.50;
	float w = 1.25;
	float e = 0.50;
	float r = 0.0;
	*/
	float q = 0.0f;
	float w = 0.0f;
	float e = 0.0f;
	float r = 0.0f;
	//front
	coor[0][0] = -q;
	coor[0][1] =  w;
	coor[0][2] = -e;

	coor[1][0] = -q;
	coor[1][1] = -r;
	coor[1][2] = -e;

	coor[2][0] =  q;
	coor[2][1] =  r;
	coor[2][2] = -e;

	coor[3][0] =  q;
	coor[3][1] =  w;
	coor[3][2] = -e;
	//back
	coor[0][0] = -q;
	coor[0][1] =  w;
	coor[0][2] = e;

	coor[1][0] = -q;
	coor[1][1] = -r;
	coor[1][2] = e;

	coor[2][0] =  q;
	coor[2][1] =  r;
	coor[2][2] = e;

	coor[3][0] =  q;
	coor[3][1] =  w;
	coor[3][2] = e;

	lastangle[0] = camera.getAngleX();
	lastangle[1] = camera.getAngleY();
	lastangle[2] = camera.getAngleZ();
}

void BMPlayer::resetView(){
	camera.reset();
}

void BMPlayer::forward(){

	if(first_person == 1){
		camera.MoveForwards(speed);
	}else{
		switch(vertical){
			case 1://top
			case 2://bottom
			case 3://right
			case 4://left
				z-=speed;
				if(direction & DIR_BACK){
					direction |= -DIR_BACK;
					if(direction & DIR_FRONT){
						direction |= -DIR_FRONT;
					}
				}else{
					if(!(direction & DIR_FRONT)){
						direction |= DIR_FRONT;
					}
					
				}
				break;
			case 5:
			case 6:
			default:
			break;
		}	
	}
	updateView();
}
void BMPlayer::back(){

	if(first_person == 1){
		camera.MoveForwards(-speed);
	}else{
		switch(vertical){
			case 1://top
			case 2://bottom
			case 3://right
			case 4://left
				z-=-speed;
				if(direction & DIR_FRONT){
					direction = direction - DIR_FRONT;
					if(direction & DIR_BACK){
						direction = direction - DIR_BACK;
					}
				}else{
					if(!(direction & DIR_BACK)){
						direction = direction + DIR_BACK;
					}
					
					
				}
				break;
			case 5:
			case 6:
			default:
			break;
		}	
	}
	updateView();
}

void BMPlayer::left(){
	if(first_person == 1){
		camera.StrafeRight (-speed);
	}else{
		switch(vertical){
			case 1://top
			case 2://bottom
			x+=-speed;
			if(direction & DIR_RIGHT){
				direction |= -DIR_RIGHT;
				if(direction & DIR_LEFT){
					direction |= -DIR_LEFT;
				}
			}else{
				if(!(direction & DIR_LEFT)){
					direction |= DIR_LEFT;
				}
				
			}
			break;
			case 3:
			case 4:
				y+=speed;
				if(direction & DIR_DOWN){
					direction |= -DIR_DOWN;
					if(direction & DIR_UP){
						direction |= -DIR_UP;
					}
				}else{
					if(!(direction & DIR_UP)){
						direction |= DIR_UP;
					}
				}
				break;
			case 5:
			case 6:
			default:
			break;
		}	
	}
	updateView();
}

void BMPlayer::right(){
	if(first_person == 1){
		camera.StrafeRight (speed);
	}else{
		switch(vertical){
			case 1://top
			case 2://bottom
			x+=speed;
			if(direction & DIR_LEFT){
				direction |= -DIR_LEFT;
				if(direction & DIR_RIGHT){
					direction |= -DIR_RIGHT;
				}
			}else{
				if(!(direction & DIR_RIGHT)){
					direction |= DIR_RIGHT;
				}
			}
			break;
			case 3:
			case 4:
			
				y+=-speed;
				if(direction & DIR_DOWN){
					direction |= -DIR_DOWN;
					if(direction & DIR_UP){
						direction |= -DIR_UP;
					}
				}else{
					if(!(direction & DIR_UP)){
						direction |= DIR_UP;
					}
				}
				break;
			case 5:
			case 6:
			default:
			break;
		}	
	}
	updateView();
}

void BMPlayer::look(SDL_Event event, int swidth, int sheight, int use_joystick, float sensitivity){
	if(first_person == 1){
		camera.mouseMove(event.motion.x, event.motion.y, swidth, sheight, use_joystick, sensitivity);
	}else{
	}
}

void BMPlayer::attack(){
}
void BMPlayer::changeWeapon(){
}

void BMPlayer::action(){
}

void BMPlayer::pickupWeapon(){
}

void BMPlayer::view(){
	camera.Render();
}

void BMPlayer::move(float mx, float my, float mz){
	BMCreature::move(mx,my,mz);
	//viewport.x = mx;
	//viewport.y = my;
	//viewport.z = mz;
	//updateView();
	//printf("x %f y %f z %f",x,y,z);

	if(first_person==1){
		if(vertical == 1 ){
			camera.setY(constview.y + y);
			camera.setX(cos(camera.getAngleY() * PIdiv180) * constview.x + x);
			camera.setZ(sin(camera.getAngleY() * PIdiv180) * constview.z + z);

		}
	}else{
	    if(vertical == 1 ){
			camera.setY(constview.y +y);
			camera.setX(x);
			camera.setZ(z+12.0f);

		}
	}
	
	model->moveModel(x,y,z);
}

void BMPlayer::updateView(){
	if(first_person == 1){
		switch(vertical){//only case 1 tested
			case 1:
				x = camera.getX() - constview.x * cos(lastangle[1] * PIdiv180);
				z = camera.getZ() - constview.z * sin(lastangle[1] * PIdiv180);
				camera.setY(constview.y + y);
				camera.setX(cos(camera.getAngleY() * PIdiv180) * constview.x + x);
				camera.setZ(sin(camera.getAngleY() * PIdiv180) * constview.z + z);
				break;
			case 2:
				x = camera.getX() - constview.x * cos(lastangle[1] * PIdiv180);
				z = camera.getZ() - constview.z * sin(lastangle[1] * PIdiv180);
				camera.setY(-constview.y + y);
				camera.setX(cos(camera.getAngleY() * PIdiv180) * constview.x + x);
				camera.setZ(sin(camera.getAngleY() * PIdiv180) * constview.z + z);
				break;
			case 3:
				y = camera.getY() - constview.y * cos(lastangle[0] * PIdiv180);
				z = camera.getZ() - constview.z * sin(lastangle[0] * PIdiv180);
				camera.setX(-constview.y + x);
				camera.setY(cos(camera.getAngleX() * PIdiv180) * constview.x + y);
				camera.setZ(sin(camera.getAngleX() * PIdiv180) * constview.z + z);
				break;
			case 4:
				y = camera.getY() - constview.y * cos(lastangle[0] * PIdiv180);
				z = camera.getZ() - constview.z * sin(lastangle[0] * PIdiv180);
				camera.setX(constview.y + x);
				camera.setY(cos(camera.getAngleX() * PIdiv180) * -constview.x + y);
				camera.setZ(sin(camera.getAngleX() * PIdiv180) * constview.z + z);
				break;
			case 5:
				x = camera.getX() - constview.x * cos(lastangle[2] * PIdiv180);
				y = camera.getY() - constview.y * sin(lastangle[2] * PIdiv180);
				//camera.setZ(constview.y + z);
				camera.setX(cos(camera.getAngleZ() * PIdiv180) * constview.x + x);
				camera.setY(sin(camera.getAngleZ() * PIdiv180) * -constview.z + y);
				break;
			case 6:
				x = camera.getX() - constview.x * cos(lastangle[2] * PIdiv180);
				y = camera.getY() - constview.y * sin(lastangle[2] * PIdiv180);
				//camera.setZ(constview.y + z);
				camera.setX(cos(camera.getAngleZ() * PIdiv180) * constview.x + x);
				camera.setY(sin(camera.getAngleZ() * PIdiv180) * constview.z + y);
				break;
			default:
			break;
		}
		
		lastangle[0] = camera.getAngleX();
		lastangle[1] = camera.getAngleY();
		lastangle[2] = camera.getAngleZ();
	}else{
	
		switch(vertical){
			case 1:
			camera.setY(constview.y + y);
			camera.setX(x);
			camera.setZ(12.0f+z);
			break;
			case 2:
			camera.setY(-constview.y + y);
			camera.setX(x);
			camera.setZ(12.0f+z);
			break;
			case 3:
			camera.setY(y);
			camera.setX(-constview.y + x);
			camera.setZ(12.0f+z);
			break;
			case 4:
			camera.setY(y);
			camera.setX(constview.y + x);
			camera.setZ(12.0f+z);
			break;
			case 5:
			camera.setY(y);
			camera.setX(x);
			camera.setZ(12.0f+z);
			break;
			case 6:
			camera.setY(y);
			camera.setX(x);
			camera.setZ(12.0f+z);
			default:
			break;
		}
		lastangle[0] = camera.getAngleX();
		lastangle[1] = camera.getAngleY();
		lastangle[2] = camera.getAngleZ();
		model->moveModel(x,y,z);
	}
}

void BMPlayer::firstPerson(){
	first_person = 1;
}

void BMPlayer::thirdPerson(){

	first_person = 0;
}
int BMPlayer::load(char filename[64]){
    model = new BMModel;
    model->initModel(MOD_OBJ, x, y, z); // init module as OBJ type
    int obj_error = 0;
    if((obj_error = model->loadModel(filename)) == 0) {
        cout << "Unable to load player model! | Error: " << obj_error << std::endl;
        return 0;
    }

    return 1;
}

void BMPlayer::draw(){
	model->drawModel();
}


int BMPlayer::jump(BMLevel *level){

	{
				cout << "\n";
				cout << "jump1: ";
				if(direction & DIR_LEFT)
					cout << "left, ";
				if(direction & DIR_RIGHT)
					cout << "right, ";
				if(direction & DIR_UP)
					cout << "up, ";
				if(direction & DIR_DOWN)
					cout << "down, ";
				if(direction & DIR_FRONT){
					cout << "front,";
				}
				if(direction & DIR_BACK){
					cout << "back ";
				}
					
	}
	float front_x = (direction & DIR_RIGHT)?(jump_dis):((direction & DIR_LEFT)?(jump_dis * -1):(0));
	float front_y = (direction & DIR_UP)?(jump_dis):((direction & DIR_DOWN)?(jump_dis * -1):(0));
	float front_z;
	/*if(z_flip){
		front_z = (direction & DIR_FRONT)?(level->getScalar() * -1):((direction & DIR_BACK)?(level->getScalar()):(0));
	}else{
	*/
		front_z = (direction & DIR_FRONT)?(jump_dis * -1):((direction & DIR_BACK)?(jump_dis ):(0));
	//}
	//for(int i=0; i < QUAD_PRISM; i++){
		//test to see if an object is worth jumping onto
		/*cout << endl << "b" << level->getBlockType((int)((x + front_x + level->getScalar()/2)/level->getScalar()),(int)((y + front_y + level->getScalar()/2)/level->getScalar()),(int)((z + front_z + level->getScalar()/2)/level->getScalar())) << endl
		<< (level->collision( x + front_x, y + front_y, z + front_z, BLOCK_12)) << endl;
		*/
		cout << "block: " << level->collision( x + front_x, y + front_y, z + front_z, BLOCK_12);
		if(level->collision( x + front_x, y + front_y, z + front_z, BLOCK_12)){
			
			//get new coordinates
			Point3D *point;
			point = level->getBlock( x + front_x,  y + front_y, z + front_z - front_z);
			cout << endl <<  " p->x:" << point->x  << " x:" << y << " f_x:" << front_x;
			cout << endl <<  " p->y:" << point->y  << " y:" << y << " f_y:" << front_y;
			cout << endl <<  " p->z:" << point->z  << " z:" << z << " f_z:" << front_z << endl;
			//set new coordinates
			int v = 0;
			switch(vertical){
				case 1://up
					v = 1;
					
					//z coor
					if(direction & DIR_FRONT && !(direction & DIR_LEFT) && !(direction & DIR_RIGHT)){
						goal_jump[2] = point->z - level->getScalar()/2 - 0.01;
						//goal_jump[2] = point->z - 0.1;
						v = 5;
					}else{
						if(direction & DIR_BACK && !(direction & DIR_LEFT) && !(direction & DIR_RIGHT)){
							goal_jump[2] = point->z + level->getScalar()/2 + 0.01;
							//goal_jump[2] = point->z + 0.1;
							v = 6;
						}else{
							goal_jump[2] = z;
						}
					}
					
					//x coor
					if(direction & DIR_RIGHT && !(direction & DIR_FRONT) && !(direction & DIR_BACK)){
						goal_jump[0] = point->x - 0.01;
						//goal_jump[0] = point->x - level->getScalar() - 0.1;
						//goal_jump[0] = point->x - 0.1;
						v = 3;
					}else{
						if(direction & DIR_LEFT && !(direction & DIR_FRONT) && !(direction & DIR_BACK)){
							goal_jump[0] = point->x + level->getScalar() + 0.01;
							//goal_jump[0] = point->x + 0.1;
							v = 4;
						}else{
							goal_jump[0] = x;
						}
						
					}
					//y coor
					//goal_jump[1] = point->y - level->getScalar()/2 ;
					goal_jump[1] = point->y +0.01;
					
					direction = DIR_UP;
					
					direction = 0;
				break;
				case 2://down
					v = 2;
					
					//z coor
					if(direction & DIR_FRONT && !(direction & DIR_LEFT) && !(direction & DIR_RIGHT)){
						goal_jump[2] = point->z - level->getScalar()/2 - 0.01;
						v = 5;
					}else{
						if(direction & DIR_BACK && !(direction & DIR_LEFT) && !(direction & DIR_RIGHT)){
							goal_jump[2] = point->z + level->getScalar()/2 + 0.01;
							v = 6;
						}else{
							goal_jump[2] = z;
						}
					}
					//x coor
					if(direction & DIR_RIGHT && !(direction & DIR_FRONT) && !(direction & DIR_BACK)){
						goal_jump[0] = point->x - 0.01;
						v = 3;
					}else{
						if(direction & DIR_LEFT && !(direction & DIR_FRONT) && !(direction & DIR_BACK)){
							goal_jump[0] = point->x + level->getScalar() + 0.01;
							v = 4;
						}else{
							goal_jump[0] = x;
						}
						
					}
					//y coor
					goal_jump[1] = point->y -0.01;
					direction = DIR_DOWN;
					
					direction = 0;
					break;
				case 3://right
					v = 3;
					//z coor
					if(direction & DIR_FRONT && !(direction & DIR_LEFT) && !(direction & DIR_RIGHT)){
						goal_jump[2] = point->z - level->getScalar()/2 - 0.01;
						v = 5;
					}else{
						if(direction & DIR_BACK && !(direction & DIR_LEFT) && !(direction & DIR_RIGHT)){
							goal_jump[2] = point->z + level->getScalar()/2 + 0.01;
							v = 6;
						}else{
							goal_jump[2] = z;
						}
					}
					//x coor
					if(direction & DIR_UP && !(direction & DIR_FRONT) && !(direction & DIR_BACK)){
						goal_jump[1] = point->y + level->getScalar()/2 +0.01;
						v = 2;
					}else{
						if(direction & DIR_DOWN && !(direction & DIR_FRONT) && !(direction & DIR_BACK)){
							goal_jump[1] = point->y - level->getScalar()/2 - 0.01;
							v = 1;
						}else{
							goal_jump[1] = y;
						}
						
					}
					//y coor
					goal_jump[0] = point->x -0.01;
					
					direction = DIR_LEFT;
					direction = 0;
					break;
				case 4://left
					v = 4;
					//z coor
					if(direction & DIR_FRONT && !(direction & DIR_LEFT) && !(direction & DIR_RIGHT)){
						goal_jump[2] = point->z - level->getScalar()/2 - 0.01;
						v = 5;
					}else{
						if(direction & DIR_BACK && !(direction & DIR_LEFT) && !(direction & DIR_RIGHT)){
							goal_jump[2] = point->z + level->getScalar()/2 + 0.01;
							v = 6;
						}else{
							goal_jump[2] = z;
						}
					}
					//y coor
					if(direction & DIR_UP && !(direction & DIR_FRONT) && !(direction & DIR_BACK)){
						goal_jump[1] = point->y + level->getScalar()/2 +0.01;
						v = 2;
					}else{
						if(direction & DIR_DOWN && !(direction & DIR_FRONT) && !(direction & DIR_BACK)){
							goal_jump[1] = point->y - level->getScalar()/2 - 0.01;
							v = 1;
						}else{
							goal_jump[1] = y;
						}
						
					}
					//x coor
					goal_jump[0] = point->x +0.01;
					
					direction = DIR_RIGHT;
					direction = 0;
					break;
				break;
				case 5://front
					v = 5;/*
					//x coor
					if(direction & DIR_RIGHT && !(direction & DIR_UP) && !(direction & DIR_DOWN)){
						goal_jump[0] = point->x - 0.01;
						v = 3;
					}else{
						if(direction & DIR_LEFT && !(direction & DIR_UP) && !(direction & DIR_DOWN)){
							goal_jump[0] = point->x + level->getScalar() + 0.01;
							v = 4;
						}else{
							goal_jump[0] = x;
						}
						
					}
					//y coor
					if(direction & DIR_UP && !(direction & DIR_RIGHT) && !(direction & DIR_LEFT)){
						goal_jump[1] = point->y + level->getScalar()/2 +0.01;
						v = 2;
					}else{
						if(direction & DIR_DOWN && !(direction & DIR_RIGHT) && !(direction & DIR_LEFT)){
							goal_jump[1] = point->y - level->getScalar()/2 - 0.01;
							v = 1;
						}else{
							goal_jump[1] = y;
						}
						
					}
					//z coor
					goal_jump[2] = point->z +0.01;
					
					direction = DIR_BACK;*/
					return 0;
				break;
				case 6://back
				
					v = 6;
					//x coor
					if(direction & DIR_RIGHT && !(direction & DIR_UP) && !(direction & DIR_DOWN)){
						goal_jump[0] = point->x - 0.01;
						v = 3;
					}else{
						if(direction & DIR_LEFT && !(direction & DIR_UP) && !(direction & DIR_DOWN)){
							goal_jump[0] = point->x + level->getScalar() + 0.01;
							v = 4;
						}else{
							goal_jump[0] = x;
						}
						
					}
					//y coor
					if(direction & DIR_UP && !(direction & DIR_RIGHT) && !(direction & DIR_LEFT)){
						goal_jump[1] = point->y + level->getScalar()/2 +0.01;
						v = 2;
					}else{
						if(direction & DIR_DOWN && !(direction & DIR_RIGHT) && !(direction & DIR_LEFT)){
							goal_jump[1] = point->y - level->getScalar()/2 - 0.01;
							v = 1;
						}else{
							goal_jump[1] = y;
						}
						
					}
					//z coor
					goal_jump[2] = point->z + level->getScalar()/2 + 0.01;
					
					direction = DIR_FRONT;
					
					direction = 0;
					//return 0;
				break;
				default:
				//cout << "default" << endl;
				return 0;
				break;
			}
			vertical = v;
			//goal_jump[0] = x;
			//goal_jump[1] = y;
			//goal_jump[2] = z;
			//temporary will change later
			x = goal_jump[0];
			y = goal_jump[1];
			z = goal_jump[2];
			updateView();
			cout << "\nx: "<< x << ", y: " << y << ", z: " << z << ", v:" << vertical << endl;
			
	{
				cout << "\n";
				cout << "jump2: ";
				if(direction & DIR_LEFT)
					cout << "left, ";
				if(direction & DIR_RIGHT)
					cout << "right, ";
				if(direction & DIR_UP)
					cout << "up, ";
				if(direction & DIR_DOWN)
					cout << "down, ";
				if(direction & DIR_FRONT){
					front_z = level->getScalar();
					cout << "front, z:" << front_z;
				}
				if(direction & DIR_BACK){
					front_z = level->getScalar() * -1;
					cout << "back ";
				}
					
	}
			return 1;
		//}
	}else{
	
			cout << endl <<   " x:" << y << " f_x:" << front_x;
			cout << endl <<   " y:" << y << " f_y:" << front_y;
			cout << endl <<   " z:" << z << " f_z:" << front_z << endl;
		}
	
	{
				cout << "\n";
				cout << "jump2: ";
				if(direction & DIR_LEFT)
					cout << "left, ";
				if(direction & DIR_RIGHT)
					cout << "right, ";
				if(direction & DIR_UP)
					cout << "up, ";
				if(direction & DIR_DOWN)
					cout << "down, ";
				if(direction & DIR_FRONT){
					front_z = level->getScalar();
					cout << "front, z:" << front_z;
				}
				if(direction & DIR_BACK){
					front_z = level->getScalar() * -1;
					cout << "back ";
				}
					
	}
			updateView();
	return 0;
}

void BMPlayer::resetDirection(){
	BMCreature::resetDirection();
}
BMPlayer::~BMPlayer(){
}
